
import { reactive } from 'vue'

// 加载日志类型
import type {
  TAnyObject,
  TStateKey
} from '../types/type'

// 深层赋值的函数
// import { deepClone } from './assign'

/**
 * 记录状态的变化日志，用key来区分
 * * stateLog = {
 * *  key: {
 * *   log: [
 * *     {
 * *       time: '时间戳',
 * *       kind: '', // 操作类型
 * *       oldValue: {},
 * *       newValue: {},
 * *       subValue: {}, // 参数
 * *       callFun: '' // 调用的函数名
 * *     }
 * *   ]
 * *  }
 * * }
 */
const stateLog = reactive({})

/**
  * 添加一个新记录
  * @param key 状态的key
  * @param kind 操作类型
  * @param oldVal 原值，序列化
  * @param newVal 新值
  * @param subVal 参数，比如 patch
  * @param _stackstr stack 拆分为数组后，记录哪个元素
  */
function addLog(
    key: TStateKey,
    kind: string,
    oldVal: string,
    newVal: TAnyObject,
    subVal: TAnyObject = {},
    _stackstr?: string
  ): void {
    if (!stateLog[key]) {
      stateLog[key] = {log: []}
    }
    if (kind === 'init') return
    
    // 获取调用者，如果没有传递的话，自己获取 $reset
    let stackstr = _stackstr
    if (!_stackstr) {
      const stackIndex = 3
      const stack: string = new Error().stack ?? ''
      const arr = stack.split('\n')
      // 记录调用的函数（组件），不支持template里触发的调用
      stackstr = arr.length > stackIndex ? arr[stackIndex]: arr[arr.length - 1]
    }

    const _oldVal = oldVal // isReactive(oldVal) ? deepClone({}, oldVal) :
    const _newVal = JSON.stringify(newVal, null, 2) // deepClone({}, newVal) // : newVal
    const _subVal = JSON.stringify(subVal, null, 2) // deepClone({}, subVal) // : subVal

    stateLog[key].log.push({
      time: new Date().valueOf(),
      kind: kind,
      oldValue: _oldVal,
      newValue: _newVal,
      subValue: _subVal,
      callFun: stackstr // 调用的函数名
    })
}

/**
 * 写日志的语法糖
 * @param me 状态，this
 * @param submitVal 触发改变的值
 * @param kind 操作类型
 * @param index 日志的位置
 * @param callback 回调函数
 */
const writeLog = async (
  me: TAnyObject,
  submitVal: TAnyObject,
  kind: string,
  index: number,
  callback: () => void
) => {
  if (!me.$isLog) {
    // 不记录日志，执行回调，退出
    await callback()
    return
  }
  // 开始记录
  // 记录调用堆栈
  const stack = new Error().stack ?? ''
  const arr = stack.split('\n')
  // 记录原值的副本
  const val1 = (me.$isObject || me.$isArray) ? me.$toRaw() : me
  const oldVal = JSON.stringify(val1, null, 2) // deepClone({}, val1)

  //执行回调，变更状态
  await callback()

  // 记录变化
  const newVal = (me.$isObject || me.$isArray) ? me.$toRaw() : me
  addLog(me.$id, kind, oldVal, newVal, submitVal, arr[index])
} 

export {
  writeLog, // 写一条日志
  stateLog, // 记录容器
  addLog // 添加一条记录
}